#include <QDir>
#include <QDomDocument>
#include "EventManager.h"

EventManager::EventManager(QString eventPath,
                           QObject *parent) :
   QObject(parent),
   theEventTable(eventPath)
{
   // Blank intentionally
}

void EventManager::reportEvents()
{
   QDir eventDir(DIR_EVENTS, QString("*" + EXT_EVENT));

   // Event files exist in directory
   if(eventDir.exists() && eventDir.count() > 0)
   {
      foreach(QFileInfo info, eventDir.entryInfoList())
      {
         QFile file(info.absoluteFilePath());
         /// @todo ftp file
         /// @todo delete if successful
      }
   }
}

void EventManager::slotRegisterPlugin(Plugin *plugin)
{
   theEventSubscriptions.insert(plugin, QList<quint32>());

   connect(plugin, SIGNAL(signalPublishEvent(Event)), this, SLOT(slotPublishEvent(Event)));
   connect(plugin, SIGNAL(signalSubscribeEvent(quint32)), this, SLOT(slotSubscribeEvent(quint32)));
   connect(plugin, SIGNAL(signalUnsubscribeEvent(quint32)), this, SLOT(slotUnsubscribeEvent(quint32)));
}

void EventManager::slotPublishEvent(Event event)
{
   foreach(Plugin *plugin, theEventSubscriptions.keys())
   {
      // Plugin is subscribed to event
      if(theEventSubscriptions.value(plugin).contains(event.id()))
      {
         connect(this, SIGNAL(signalEventNotification(Event)), plugin, SLOT(slotEventNotification(Event)));
         emit signalEventNotification(event);
         disconnect(this, SIGNAL(signalEventNotification(Event)), plugin, SLOT(slotEventNotification(Event)));
      }
   }

   recordEvent(event);
   reportEvents();
}

void EventManager::slotSubscribeEvent(quint32 id)
{
   IPlugin *interface = qobject_cast<IPlugin*>(this->sender());
   Plugin *plugin = interface->getPlugin();

   theEventSubscriptions[plugin].append(id);
}

void EventManager::slotUnsubscribeEvent(quint32 id)
{
   IPlugin *interface = qobject_cast<IPlugin*>(this->sender());
   Plugin *plugin = interface->getPlugin();

   theEventSubscriptions[plugin].removeAll(id);
}

bool EventManager::recordEvent(Event event)
{
   bool success = false;

   // Verify event exists
   if(findEvent(event))
   {
      // Verify event has valid attributes
      if(event.id() != INVALID_ID && event.category() != Event::INVALID)
      {
         QString serializedMessage = event.serializeEvent();

         // Serialization failure will return an empty string
         if(!serializedMessage.isEmpty())
         {
            QString fileName = DIR_EVENTS + QDateTime::currentDateTimeUtc().toString(TIMESTAMP_FORMAT) + EXT_EVENT;
            QFile eventFile(fileName);

            // Create event file
            if(eventFile.open(QIODevice::WriteOnly))
            {
               // Write serialized message to file
               success = eventFile.write(serializedMessage.toStdString().c_str()) == serializedMessage.size();
               eventFile.close();
            }
         }
      }
   }

   return success;
}

bool EventManager::findEvent(Event event)
{
   bool success = false;
   QDomDocument xml;
   xml.setContent(&theEventTable);

   QDomNodeList eventElements = xml.documentElement().childNodes();   // Get list of events elements

   // Loop through event elements
   for(quint32 i = 0; i < eventElements.length(); i++)
   {
      QDomElement eventElement = eventElements.at(i).toElement();

      if(eventElement.hasChildNodes())
      {
         quint32 id = eventElement.firstChildElement("ID").text().toUInt();
         QString category = eventElement.firstChildElement("Category").text();
         QString name = eventElement.firstChildElement("Name").text();
         QString message = eventElement.firstChildElement("Message").text();

         // Event IDs match
         if(id == event.id())
         {
            success = true;
            event.setCategory(getCategory(category));
            event.setName(name);
            event.setMessage(message);
         }
      }
   }

   return success;
}

Event::Category EventManager::getCategory(QString category)
{
   if(category == "Catastrophic")
   {
      return Event::CATASTROHPIC;
   }
   else if(category == "Critical")
   {
      return Event::CRITICAL;
   }
   else if(category == "Cautionary")
   {
      return Event::CAUTIONARY;
   }
   else if(category == "Operational")
   {
      return Event::OPERATIONAL;
   }
   else
   {
      return Event::INVALID;
   }
}
